﻿using Digitalmes.Application.Sys.Users.Queries;
using Digitalmes.WebApi.Infrastructure.Jwt;

namespace Digitalmes.WebApi.Endpoints;

/// <summary>
/// 用户验证终结点。
/// </summary>
public sealed class AuthEndpoint : EndpointGroupBase
{
    public override void Map(WebApplication app)
    {
        app.MapGroup(this)
            .MapPost(LoginAsync, "login")
            .MapPost(RefreshToken, "refresh-token");
    }

    /// <summary>
    /// 账户密码登录
    /// </summary>
    /// <returns></returns>
    public async Task<IApiResult> LoginAsync(LoginViewModel model, ISender sender, IJwtAuthManager jwtAuthManager, TimeProvider time, IOptions<JwtTokenConfig> options)
    {
        var user = (await sender.Send(new GetUserByNameQuery(model.UserName))).Value;
        if (user == null ||
            user.Status == EnabledStatusEnum.Disabled ||
            CryptoUtils.MDString(model.Password) != user.Password)
        {
            return ApiResult.Bad();
        }

        JwtToken token = new()
        {
            UserId = user.Id,
            UserName = user.UserName,
            Roles = user.UserRoles
                .Where(s => s.SysRole?.Status == EnabledStatusEnum.Enabled)
                .Select(s => s.SysRole!.Code)
                .ToList(),
        };

        var now = time.GetLocalNow().DateTime;
        var accessTokenExp = TimeSpan.FromMinutes(options.Value.AccessTokenExpiration);
        var refreshTokenExp = TimeSpan.FromMinutes(options.Value.RefreshTokenExpiration);

        var resp = new
        {
            userId = token.UserId,
            username = token.UserName,
            nickname = user.Nickname,
            avatar = user.Avatar,
            roles = token.Roles,

            accessToken = jwtAuthManager.GenerateToken(token, now, accessTokenExp),
            refreshToken = jwtAuthManager.GenerateToken(token, now, refreshTokenExp),
            expires = now.Add(accessTokenExp),
        };

        return ApiResult.Ok(resp);
    }

    /// <summary>
    /// 获取刷新Token（以旧换新）
    /// </summary>
    /// <returns></returns>
    public IApiResult RefreshToken(RefreshTokenViewModel model, IJwtAuthManager jwtAuthManager, TimeProvider time, IOptions<JwtTokenConfig> options)
    {
        var now = time.GetLocalNow().DateTime;
        var accessTokenExp = TimeSpan.FromMinutes(options.Value.AccessTokenExpiration);
        var refreshTokenExp = TimeSpan.FromMinutes(options.Value.RefreshTokenExpiration);

        var resp = new
        {
            accessToken = jwtAuthManager.Refresh(model.RefreshToken!, now, accessTokenExp),
            refreshToken = jwtAuthManager.Refresh(model.RefreshToken!, now, refreshTokenExp),
            expires = now.Add(accessTokenExp),
        };
        return ApiResult.Ok(resp);
    }
}
